/*
 *   This File is Part of CuteOgre Game Engine
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *	Copyright 2010 Alexandre Pires ( c.alexandre.pires@gmail.com )
 *  Created on: 2010/08/22
 */

#include "ScriptManager.h"
#include "ConfigManager.h"
#include "LogManager.h"
#include "ConfigFunctions.h"
#include "StateFunctions.h"
#include "VideoPlayerFunctions.h"

#include <QStringList>

#include "OGRE/OgreResourceManager.h"
#include "OGRE/OgreDataStream.h"

template<> ScriptManager* Singleton<ScriptManager>::ms_Singleton = 0;

void ScriptManager::setupEnvironment ( QScriptEngine* rEngine ) {

	rEngine->globalObject ().setProperty ( "configGetParam",
			rEngine->newFunction ( configGetParam, 2 ) );
	rEngine->globalObject ().setProperty ( "configSetParam",
			rEngine->newFunction ( configSetParam, 3 ) );

	rEngine->globalObject ().setProperty ( "changeState", rEngine->newFunction (
			changeState, 2 ) );
	rEngine->globalObject ().setProperty ( "pushState", rEngine->newFunction (
			pushState, 3 ) );
	rEngine->globalObject ().setProperty ( "popState", rEngine->newFunction (
			popState, 0 ) );

	rEngine->globalObject ().setProperty ( "addVideoToPlayList",
			rEngine->newFunction ( addVideoToPlayList ) );

	loadScript("core/class.js", rEngine, false );
	loadScript("core/gamestates.js", rEngine, false );
}

bool ScriptManager::loadScript ( const QString& rFile, QScriptEngine* rEngine, bool rPush ) {
	LogManager::message(QString("ScriptManager::Loading Script %1").arg(rFile));
	QString contents = readFileContents ( rFile );
	return evaluateScript ( contents, rEngine, rPush );
}

QScriptValue ScriptManager::importScript ( const QString& rFile, QScriptEngine* rEngine ) {
	return rEngine->undefinedValue ();
}

bool ScriptManager::evaluateScript ( const QString& content, QScriptEngine* rEngine, bool rPush ) {

	LogManager::message("ScriptManager::Evaluating Script");

	if ( rPush )
		rEngine->pushContext();

	QScriptValue result = rEngine->evaluate ( content );

	if ( rEngine->hasUncaughtException () ) {

		QStringList backtrace = rEngine->uncaughtExceptionBacktrace ();
		LogManager::message(QString("ScriptManager::Uncaught Exception %1\n%2\n\n").arg(result.toString()).arg(backtrace.join("\n")));
		rEngine->clearExceptions ();

		if ( rPush )
			rEngine->popContext();

		return false;
	}

	if ( rPush )
		rEngine->popContext();

	return true;
}

void ScriptManager::init () {

	if ( !mShutdown )
		return;

	LogManager::message("ScriptManager:: Starting up");

	QString str = ConfigManager::readString ( "ScriptsPath", "Data/Scripts;" );

	if ( str.endsWith(';') )
		str.chop(1);

	QStringList urls = str.split ( ';' );

	Ogre::ResourceGroupManager* mngr =
			&Ogre::ResourceGroupManager::getSingleton ();

	foreach ( QString url, urls )
			mngr->addResourceLocation ( url.toStdString(), "FileSystem", "Scripts" );

	mShutdown = false;
}

void ScriptManager::shutdown () {

	if ( mShutdown )
		return;

	LogManager::message("ScriptManager:: Shutting down");

	mShutdown = true;
}

QString ScriptManager::readFileContents ( const QString& rFile ) {

	Ogre::ResourceGroupManager* resourceManager =
			&Ogre::ResourceGroupManager::getSingleton ();

	if ( !resourceManager->resourceExists ( "Scripts", rFile.toStdString () ) ) {
		LogManager::message(QString("ScriptManager::Cannot find %1 in scripts directory").arg(rFile));
		return QString::null;
	}

	Ogre::DataStreamPtr scriptStream = resourceManager->openResource (
			rFile.toStdString () );

	QString contents;

	while ( !scriptStream->eof () ) {

		QString line = QString ().fromStdString (
				scriptStream->getLine ( false ) );

		contents.append ( line + "\n" );
	}

	return contents;
}
